<?php

namespace app\admin\controller\coursetable;

use app\admin\controller\subjectlv\Subjectlv;
use app\admin\library\CommunityRedis;
use app\common\controller\Backend;
use app\admin\library\ClassesObject;
use app\admin\library\ClassplanObject;
use think\db;
use Exception;
use fast\Tree;
use app\admin\library\SchoolScheduler;
use think\Request;
use app\admin\library\SchoolRedis;
use app\admin\library\Auth;


/**
 *
 *
 * @icon fa fa-file
 */
class Autoplan extends Backend
{

    /**
     * Autoplan模型对象
     */
    protected $model = null;
    protected $multiFields = 'status';
    protected $noNeedRight = ["lists", "status", "export", "export2", "redo", "checkFormalSchedule", "confirmSchedule", "clear", "cancelSchedule"];
    protected $noNeedLogin = ["lists", "status", "export", "export2", "redo", "checkFormalSchedule", "confirmSchedule", "clear", "cancelSchedule"];
    public $redis;
    public $auth;
    public function __construct()
    {
        parent::__construct(); // 调用父类构造函数
        $this->redis = new SchoolRedis();
        $this->request = Request::instance();
        $this->auth = new Auth();
    }

    /**
     * 检查排课是否已过期
     * @param array|int $schedule 排课记录或ID
     * @return bool
     */
    protected function isScheduleExpired($schedule)
    {
        if (is_numeric($schedule)) {
            $schedule = $this->model->find($schedule);
            if (!$schedule) {
                return true; // 如果记录不存在，视为已过期
            }
        }

        // 检查date字段是否存在且不为空
        if (!isset($schedule['date']) || empty($schedule['date'])) {
            return false; // 如果没有日期信息，不视为过期
        }

        // 转换为时间戳比较
        $scheduleDate = strtotime($schedule['date']);
        $today = strtotime(date('Y-m-d'));

        return $scheduleDate < $today;
    }


    public function _initialize()
    {
        parent::_initialize();
        $this->model = model('Autoplan');
        $this->modelValidate = true;

        // 修改为从fa_course_table表获取项目列表数据
        $tableList = Db::name('course_table')
            ->where('status', 1)
            ->field('id,name as project_name')  // 使用别名保持前端兼容性
            ->order('id desc')
            ->select();

        // 添加空值检查
        if ($this->view !== null) {
            $this->view->assign('tableList', $tableList);
        }
    }

    /**
     * 检查项目是否已有正式排课记录
     */
    public function checkFormalSchedule()
    {
        $publicwelfare_id = $this->request->param('table_id');

        if (empty($publicwelfare_id)) {
            return json([
                'code' => 0,
                'msg' => '项目ID不能为空',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        // 检查 fa_course_table_autoplan 表中是否存在该项目的记录
        $count = Db::name('course_table_autoplan')
            ->where('table_id', $publicwelfare_id)
            ->count();

        return json([
            'code' => 1,
            'msg' => '检查完成',
            'data' => ['has_formal' => $count > 0],
            'url' => null,
            'wait' => 3
        ]);
    }

    /**
     * 检查指定table_id是否已有正式排课记录（内部方法）
     * @param int $table_id 项目ID
     * @return bool
     */
    private function hasFormalSchedule($table_id)
    {
        if (empty($table_id)) {
            return false;
        }

        $count = Db::name('course_table_autoplan')
            ->where('table_id', $table_id)
            ->count();

        return $count > 0;
    }

    /**
     * 正式排课
     */
    public function confirmSchedule()
    {
        $table_id = $this->request->param('table_id');

        if (empty($table_id)) {
            \think\Log::error('confirmSchedule失败：项目ID为空');
            return json([
                'code' => 0,
                'msg' => '项目ID不能为空',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        try {
            // 检查是否已有正式排课数据
            $existCount = Db::name('course_table_autoplan')
                ->where('table_id', $table_id)
                ->count();

            if ($existCount > 0) {
                $deleteResult = Db::name('course_table_autoplan')
                    ->where('table_id', $table_id)
                    ->delete();
            }

            // 从临时表获取数据
            $tempData = Db::name('course_table_autoplan_temp')
                ->where('table_id', $table_id)
                ->select();

            if (empty($tempData)) {
                return json([
                    'code' => 0,
                    'msg' => '没有找到该项目的临时排课数据，请先进行自动排课',
                    'data' => null,
                    'url' => null,
                    'wait' => 3
                ]);
            }

            // 直接复制插入到正式表（两表结构相同）
            $insertData = [];
            foreach ($tempData as $item) {
                // 转换为数组格式并验证
                if (is_object($item)) {
                    $itemArray = $item->toArray();
                } elseif (is_array($item)) {
                    $itemArray = $item;
                } else {
                    continue; // 跳过无效数据
                }

                // 确保$itemArray是有效数组
                if (!is_array($itemArray)) {
                    continue;
                }

                // 保留临时表的id字段，因为两表结构完全相同
                // 不删除id字段，直接使用临时表的id

                // 更新时间戳
                $itemArray['create_time'] = time();
                $itemArray['update_time'] = time();
                $itemArray['t_id'] = $item['id'];
                unset($itemArray['id']);
                $insertData[] = $itemArray;
            }

            // 批量插入数据（保留原始id）
            $insertResult = Db::name('course_table_autoplan')->insertAll($insertData);

            // 插入正式表成功后，立即清空该 table_id 的临时表数据
            if ($insertResult) {
                Db::name('course_table_autoplan_temp')
                    ->where('table_id', $table_id)
                    ->delete();
            }

            return json([
                'code' => 1,
                'msg' => '正式排课成功，共处理 ' . count($insertData) . ' 条记录，临时表数据已清空',
                'data' => [
                    'processed_count' => count($insertData),
                    'table_id' => $table_id
                ],
                'url' => null,
                'wait' => 3
            ]);
        } catch (\Exception $e) {
            return json([
                'code' => 0,
                'msg' => '正式排课失败：' . $e->getMessage(),
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 清空项目排期
     */
    public function clear()
    {
        $table_id = $this->request->param('table_id');


        if (empty($table_id)) {
            return json([
                'code' => 0,
                'msg' => '项目ID不能为空',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        try {
            // 检查临时表中是否有数据
            $count = Db::name('course_table_autoplan_temp')
                ->where('table_id', $table_id)
                ->count();
            $this->redis->clearCacheByTableId($table_id);
            if ($count == 0) {
                return json([
                    'code' => 1,
                    'msg' => '清空成功（临时表无数据）',
                    'data' => null,
                    'url' => null,
                    'wait' => 3
                ]);
            }

            // 清空fa_course_table_autoplan_temp表中table_id=选中项目ID的记录
            $deleteResult = Db::name('course_table_autoplan_temp')
                ->where('table_id', $table_id)
                ->delete();

            return json([
                'code' => 1,
                'msg' => '清空成功，共删除 ' . $deleteResult . ' 条记录',
                'data' => [
                    'deleted_count' => $deleteResult,
                    'table_id' => $table_id
                ],
                'url' => null,
                'wait' => 3
            ]);
        } catch (\Exception $e) {
            return json([
                'code' => 0,
                'msg' => '清空失败：' . $e->getMessage(),
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
     * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
     * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
     */

    /**
     * 解析禁用时段和禁用课节
     * @param string $disable_week_range 禁用时段范围
     * @param string $disable_week_time 禁用课节时间
     * @return array
     */
    private function parseDisableRanges($disable_week_range, $disable_week_time)
    {
        $disabled_ranges = [];
        $disabled_times = [];

        if (!empty($disable_week_range)) {
            $ranges = explode(',', $disable_week_range);
            foreach ($ranges as $range) {
                list($day, $time) = explode(' ', trim($range));
                $disabled_ranges[] = [$day, $time];
            }
        }

        if (!empty($disable_week_time)) {
            $times = explode(',', $disable_week_time);
            foreach ($times as $time) {
                list($day, $section) = explode(' ', trim($time));
                $disabled_times[] = [$day, intval(str_replace('节', '', $section))];
            }
        }

        return [$disabled_ranges, $disabled_times];
    }

    /**
     * 查看排课信息
     * 这是排课系统的核心方法，负责显示排课结果、生成新的排课计划以及处理各种排课相关的操作
     */
    public function index()
    {
        set_time_limit(300);
        // 移除分页参数，一次性加载所有记录
        // $page = input('page/d', 1);
        // $limit = input('limit/d', 30);
        // $offset = ($page - 1) * $limit;
        // 在方法开始就定义weekdays变量，确保整个方法都能访问
        $message = "";
        $weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
        $daytimes = ['上午', '中午', '下午', '晚上'];
        // 初始化rows变量
        $rows = array();
        //设置过滤方法
        $this->request->filter(['strip_tags']);
        $table_id = $this->request->request('table_id');
        if ($this->request->isAjax()) {
            //如果发送的来源是Selectpage，则转发到Selectpage
            if ($this->request->request('keyField')) {
                return $this->selectpage();
            }

            // 获取城市和学校过滤参数
            $city_id = $this->request->get("city_id");
            $school_id = $this->request->get("school_id");

            // 调试日志
            error_log("Autoplan Index - city_id: $city_id, school_id: $school_id, table_id: $table_id");

            // 生成缓存键
            $search = $_REQUEST['search'] ?? '';
            $rel_type = $_REQUEST['rel_type'] ?? null;
            $cacheKey = $this->redis->generateCacheKey($table_id, $search, $rel_type);

            // 尝试从Redis获取缓存数据
            $cachedResult = $this->redis->getCacheData($cacheKey);
            if ($cachedResult !== false && count($cachedResult['rows']) > 0) {
                //return json($cachedResult);
            }

            // 移除分页参数，直接查询所有记录
            $this->model = model("Autoplantemp")->alias("Autoplantemp");
            // 不再需要单独计算总数，直接获取所有记录
            $apply_form = Db::name('eb_apply_form')->where(['table_id' => $_REQUEST["table_id"]])->find();
            $apply_form_id = $apply_form['id'] ?? 0;

            // 先检查是否有临时数据
            $tempModel = model("Autoplantemp")->alias("Autoplantemp");
            $tempCount = $tempModel->where("status", "<>", -1)->where("table_id", "=", $table_id)->count();
            $isFormalSchedule = $this->hasFormalSchedule($table_id); // 检查是否已有正式课表记录
            if ($tempCount == 0 && !$isFormalSchedule) {

                // 移除分页参数，直接查询所有记录
                // 不再需要单独计算总数
                $list = $tempModel->alias("Autoplantemp")
                    ->join("eb_classes", "eb_classes.id=Autoplantemp.classes_id")
                    ->field('Autoplantemp.*');
                // 添加课程ID条件
                if (isset($table_id) && $table_id != "") {
                    $list = $list->where("Autoplantemp.table_id", "=", $table_id);
                }
                if (isset($_REQUEST['search']) && $_REQUEST['search'] != "") {
                    $list = $list->where("eb_classes.name", "like", "%" . $_REQUEST['search'] . "%");
                }

                // 处理rel_type参数筛选社区数据
                if (isset($_REQUEST['rel_type'])) {
                    $rel_type = intval($_REQUEST['rel_type']);
                    if ($rel_type == 2) {
                        // 社区数据：只显示社区班级
                        $list = $list->where("Autoplantemp.table_type", "=", 2);

                        // 添加城市和学校过滤
                        if (!empty($city_id)) {
                            $list = $list->where("Autoplantemp.city_id", "=", $city_id);
                        } else if (!empty($school_id)) {
                            $list = $list->where("Autoplantemp.school_id", "=", $school_id);
                        } else if (isset($_SESSION['think']['admin']['school_id']) && $_SESSION['think']['admin']['school_id']) {
                            $list = $list->where("Autoplantemp.school_id", "=", $_SESSION['think']['admin']['school_id']);
                        }
                    } else {
                        // 学校数据：只显示学校班级
                        $list = $list->where("Autoplantemp.table_type", "=", 1);

                        // 添加城市和学校过滤
                        if (!empty($city_id)) {
                            $list = $list->where("Autoplantemp.city_id", "=", $city_id);
                        } else if (!empty($school_id)) {
                            $list = $list->where("Autoplantemp.school_id", "=", $school_id);
                        } else if (isset($_SESSION['think']['admin']['school_id']) && $_SESSION['think']['admin']['school_id']) {
                            $list = $list->where("Autoplantemp.school_id", "=", $_SESSION['think']['admin']['school_id']);
                        }
                    }
                }

                //if ($_SESSION['think']['admin']['group_id'] == 2) {
                //    $list = $list->where("city_id", "=", $_SESSION['think']['admin']['city_id']);
                //}
                // 移除分页限制，一次性加载所有记录
                $list = $list->order('Autoplantemp.weigh desc,Autoplantemp.id')
                    ->select();
                $list = collection($list)->toArray();
                foreach ($list as $entry) {
                    $array = array();
                    $array['id'] = $entry['id'];
                    $array['table_id'] = model("Coursetable")->getCoursetable_idTextAttr($entry['table_id']);
                    $array['classes_id'] = model("Classes")->getClasses_idTextAttr($entry['classes_id']) . " (" . $entry['class_index'] . "/" . $entry['count_total'] . ")";
                    $array['ocation_id'] = model("Ocation")->getOcation_idTextAttr($entry['ocation_id']);
                    $array['subject_lv'] = model("Subjectlv")->getSubjectlv_idTextAttr($entry['subject_lv']);
                    $array['addresslv_id'] = model("User")->getUser_idTextAttr($entry['addresslv_id']);
                    $array['teacher_id'] = model("User")->getUser_idTextAttr($entry['teacher_id']);
                    $array['manager_id'] = model("User")->getUser_idTextAttr($entry['manager_id']);
                    $array['date'] = $entry['date'] . " " . $entry['start_time'] . "-" . $entry['end_time'];
                    $array['week'] = $entry['week'];
                    $array['daytime'] = $entry['daytime'];
                    $array['oindex'] = "该教室当天第" . preg_replace("/课|节/", "", $entry['class_index']) . "/" . $entry['count_total'] . "节课";
                    $array['bz'] = $entry['bz'];
                    // 关键：加上is_formal字段
                    $array['is_formal'] = isset($isFormalSchedule) && $isFormalSchedule ? true : false;

                    // 检查事件是否已过期（不能编辑和删除）
                    $array['is_expired'] = $this->isScheduleExpired($entry);
                    $rows[] = $array;
                }

                // 返回所有记录，总数等于记录数
                $total = count($rows);
                $result = array(
                    "total" => $total,
                    "rows" => $rows,
                    "all_loaded" => true,
                    "has_formal_schedule" => isset($isFormalSchedule) ? $isFormalSchedule : false
                );
                if ($total > 0) {
                    $result['rows'] = $rows;
                } else {

                    // 开始重新生成排课
                    // 创建班级对象，用于获取教室时间和可用性信息
                    $classesObject = new ClassesObject();
                    $classesObject->setTableId($table_id);
                    $classroomTime = $classesObject->getClassroomTime();
                    $classroomAvailability = $classesObject->classroomAvailability;
                    
                    // 创建课程计划对象，用于处理课程计划相关逻辑
                    $classplanObject = new ClassplanObject();
                    $classplanObject->setTableId($table_id);
                    // 获取课程表信息（项目信息）
                    $r = model("Coursetable")->where("status", "=", 1)->where("id", "=", $table_id)->select();
                    $coursetable_name = $r[0]["name"]; //课程项目名称
                    $classeseids = explode(",", $r[0]["classes_id"]);
                    $startDate = $r[0]['start_date'] ? substr($r[0]['start_date'], 0, 10) : date('Y-m-d');
                    $endDate = "2028-01-01";

                    // 获取班级课程计划信息
                    $r = model("Classplant")->where("status", "=", 1)->where("table_id", "=", $table_id)->where("classes_id", "in", $classeseids)->select();
                    $data = [];
                    // 遍历每个班级的课程计划，构建成排课所需的数据结构
                    for ($i = 0; $i < count($r); $i++) {
                        $row = $r[$i];
                        $classesname = model("Classes")->getClasses_idTextAttr($row["classes_id"]);
                        $data[$classesname] = array();
                        $data[$classesname]["class_id"] = $row["id"];               // 班级计划ID
                        $data[$classesname]["classes_id"] = $row["classes_id"];     // 班级ID
                        $data[$classesname]["type"] = model("Subjectlv")->getSubject_lvTextAttr($row["subject_lv"]);
                        $data[$classesname]["type"] = $data[$classesname]["type"] == "" ? "语言" : $data[$classesname]["type"];
                        $data[$classesname]["subject_lv"] = $row["subject_lv"];     // 学科等级
                        $data[$classesname]["addresslv_id"] = $row["addresslv_id"]; // 地址等级ID
                        $data[$classesname]["count"] = $row["ocourse_count"];       // 剩余课程数量
                        $data[$classesname]["count_total"] = $row["ocourse_count"]; // 总课程数量
                        $data[$classesname]["classroom_type"] = explode(",", $row["ocation_type"]);
                        $data[$classesname]["classroom_type"] = empty($data[$classesname]["classroom_type"]) || $data[$classesname]["classroom_type"][0] == "" ? ["1", "2", "3", "4"] : $data[$classesname]["classroom_type"];
                        $data[$classesname]["classroom_type"] = array_map(function ($v) {
                            return model("Ocation")->getOcation_typeTextAttr($v);
                        }, $data[$classesname]["classroom_type"]);
                        $data[$classesname]["start_date"] = $row["start_date"] ? substr($row["start_date"], 0, 10) : date('Y-m-d');
                        $data[$classesname]["allow_multiple_classes_per_day"] = $row["can_same_day"] ? true : false;  // 是否允许同一天上多节课
                        $data[$classesname]["fixed_classroom"] = $row["same_classroom"] ? true : false;            // 是否固定教室
                        $data[$classesname]["disabled_times"] = week_daytime($row["disable_week_range"]);         // 禁用时间
                        $data[$classesname]["allowed_days"] = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; // 允许排课的日期
                        $data[$classesname]["required_times"] = week_daytime($row["must_week_range"]);            // 必须排课的时间
                        $data[$classesname]["max_classes_per_week"] = $row["classes_per_week"];                   // 每周最大课程数
                        $data[$classesname]["teacher"] = $row["teacher_id"];          // 教师ID
                        $data[$classesname]["manager"] = $row["manager_id"];          // 管理员ID
                        $data[$classesname]["nearby_classrooms"] = []; //请设为空，因为不知道安排哪个教室
                    }
                    $courses = $data; // 排课数据结构

                    // 调用排课调度器进行自动排课
                    $scheduler = new SchoolScheduler($table_id, $classroomAvailability, $classroomTime, $classplanObject, $courses, $startDate, $endDate, $apply_form_id);
                    $scheduleResult = $scheduler->autoSchedule();
                    $schedule = $scheduleResult['schedule'];
                    $message = $scheduleResult['message'];
                    $requiredTimesFailed = $scheduleResult['requiredTimesFailed'] ?? [];
                    $nearbyClassroomsFailed = $scheduleResult['nearbyClassroomsFailed'] ?? [];
                }

                // 初始化变量，避免未定义错误（如果还没有定义的话）
                if (!isset($requiredTimesFailed)) {
                    $requiredTimesFailed = [];
                }
                if (!isset($nearbyClassroomsFailed)) {
                    $nearbyClassroomsFailed = [];
                }


                // 检查是否有未排的必排时间段

                if (!empty($requiredTimesFailed)) {
                    foreach ($requiredTimesFailed as $entry) {
                        $message .= "警告: " . $entry['班名'] . " 在 " . $entry['日期'] . " " . $entry['周几'] . " " . $entry['时段'] . " 未排上课。" . $entry['备注'] . "\n<br>";
                    }
                }

                // 检查是否有未排课的班级
                if (!empty($courses)) {
                    foreach ($courses as $class => $course) {
                        if ($course['count'] > 0) {
                            $message .= "警告: {$class} 还有 {$course['count']} 节课未安排。\n<br>";
                        }
                    }
                } else {
                    // 处理$courses为空的情况
                    $message .= "警告: 没有找到可安排的课程。\n<br>";
                }

                // 确保$class变量有默认值，避免后续使用时出现未定义错误
                if (!isset($class)) {
                    $class = '';
                }
                $daytimes = ['上午', '中午', '下午', '晚上'];
            } else {
                if ($isFormalSchedule) {
                    $this->model = model("Autoplan")->alias("Autoplan");
                } else {
                    $this->model = model("Autoplantemp")->alias("Autoplantemp");
                }
                $list = $this->model->where("status", "<>", -1)
                    ->where("table_id", "=", $table_id)
                    ->order('date asc')
                    ->select();
                $list = collection($list)->toArray();
                $total = count($list);
                $rows = [];
                foreach ($list as $entry) {
                    $array = array();
                    $array['id'] = $entry['id'];
                    $array['table_id'] = model("Coursetable")->getCoursetable_idTextAttr($entry['table_id']);
                    $array['classes_id'] = model("Classes")->getClasses_idTextAttr($entry['classes_id']) . " (" . $entry['class_index'] . "/" . $entry['count_total'] . ")";
                    $array['ocation_id'] = model("Ocation")->getOcation_idTextAttr($entry['ocation_id']);
                    $array['area_teaching_ocation_id'] = model("Ocation")->getOcation_idTextAttr($entry['area_teaching_ocation_id']);
                    $array['subject_lv'] = model("Subjectlv")->getSubjectlv_idTextAttr($entry['subject_lv']);
                    $array['date'] = $entry['date'] . " " . $entry['start_time'] . "-" . $entry['end_time'];
                    $array['week'] = $entry['week'];
                    $array['daytime'] = $entry['daytime'];
                    $array["teacher_id"] = model("User")->getUser_idTextAttr($entry['teacher_id']);
                    $array["manager_id"] = model("User")->getUser_idTextAttr($entry['manager_id']);
                    //$array['teacher_id'] = $entry['teacher_id'];
                    //查询该班级的报名人数
                    $array['apply_num'] = Db::name('eb_apply_form_item')
                        ->where('classes_id', $entry['classes_id'])
                        ->count();

                    //查询该班级在上课时间点前两小时和上课后120分钟内打卡的用户人数
                    $classStartTime = $entry['date'] . " " . $entry['start_time'];
                    $clockStartTime = date('Y-m-d H:i:s', strtotime($classStartTime) - 7200); // 2小时前
                    $clockEndTime = date('Y-m-d H:i:s', strtotime($classStartTime) + 7200); // 120分钟后
                    $array['real_num'] = Db::name('user_clock')
                        ->where(function ($query) use ($clockStartTime, $classStartTime, $clockEndTime) {
                            $query->where(function ($query) use ($clockStartTime, $classStartTime) {
                                $query->where('clock_time', '>=', $clockStartTime)
                                    ->where('clock_time', '<=', $classStartTime);
                            })
                                ->whereOr(function ($query) use ($classStartTime, $clockEndTime) {
                                    $query->where('clock_time', '>=', $classStartTime)
                                        ->where('clock_time', '<=', $clockEndTime);
                                });
                        })
                        ->where('user_id', 'in', function ($query) use ($entry) {
                            $query->name('eb_apply_form_item')
                                ->where('classes_id', $entry['classes_id'])
                                ->field('user_id');
                        })->group('user_id')
                        ->count();
                    //Db::name('user_clock')->getLastSql();
                    $array['oindex'] = "该教室当天第" . $entry['oindex'] . "/" . $entry['oindex_count'] . "节课";
                    $array['bz'] = $entry['bz'];
                    $rows[] = $array;
                }
            }
            $message .= "<style>
#auto {
        border-collapse: collapse;
        width: 100%;
        margin-bottom: 20px;
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
    }
    #auto .fixed-row th {
        background-color: #e8f5e9; /* 淡绿色背景 */
        color: #2e7d32; /* 深绿色文字 */
        font-weight: 600;
        padding: 12px;
        text-align: center;
        border-bottom: 2px solid #c8e6c9;
    }
    #auto th, #auto td {
        border: 1px solid #c8e6c9;
        padding: 10px;
        text-align: center;
        min-width: 100px;
        height: 30px;
    }
    #auto th.dblclick {
        cursor: pointer;
    }
    #auto tr:hover {
        background-color: #f1f8e9; /* 鼠标悬停时的淡绿色背景 */
    }
    #auto td {
        transition: background-color 0.3s ease;
    }
</style>";
            $data = model("Autoplantempjson")->where(['table_id' => $table_id])->find();
            $schedule = !empty($data["json"]) ? json_decode($data["json"], true) : []; // 获取排班数据
            $Ocations = model("Ocation")->select(); // 获取所有教室信息
            $ocationsClass = array();
            if (!empty($schedule)) {
                foreach ($schedule as $row) {
                    $row['教室'] = trim(preg_replace("/\((?:标准|肢体|书画|综合)\)/Uisx", "", $row['教室']));
                    $ocationsClass[$row['教室']][$row['周几']][$row['start_time']] = trim($row['班名']);
                }
            }

            // 开始构建排课表HTML
            $message .= "<table id='auto'>";
            // 添加表头行：教学点、教室、时间段和周一到周日
            $message .= "<tr class='fixed-row'><th class='dblclick'>教学点</th><th class='dblclick'>教室</th>";
            $message .= "<th>时间段</th>";
            // 添加周一到周日表头
            foreach ($weekdays as $day) {
                $message .= "<th>$day</th>";
            }
            $message .= "</tr>";

            // 处理教室数据，按父级ID分组排序
            $Ocations = collection($Ocations)->toArray();
            $Ocations = array_reverse($Ocations); // 反转数组，使排序更直观
            $newOcations = array();
            $oldpid = "";
            $samepid = array(); // 初始化变量

            // 遍历所有教室，按父级ID分组
            foreach ($Ocations as $room) {
                // 初始化父级ID
                if ($oldpid == "") {
                    $oldpid = $room['pid'];
                }

                // 如果当前教室的父级ID与上一个相同，则加入同一组
                if ($room['pid'] == $oldpid) {
                    $samepid[] = $room;
                } else {
                    // 处理完一个父级ID的所有子项，进行排序
                    $oldpid = $room['pid'];
                    usort($samepid, function ($a, $b) {
                        if ($a['id'] === $b['id']) {
                            return 0;
                        }
                        return $a['id'] > $b['id'] ? 1 : -1;
                    });

                    // 防止空数组
                    if (empty($samepid)) {
                        $samepid[] = $room;
                    }

                    // 合并已排序的教室数据
                    $newOcations = array_merge($newOcations, $samepid);
                    $samepid = array($room);

                    // 处理最后一个教室
                    if ($room['id'] == end($Ocations)['id']) {
                        usort($samepid, function ($a, $b) {
                            if ($a['id'] === $b['id']) {
                                return 0;
                            }
                            return $a['id'] > $b['id'] ? 1 : -1;
                        });
                        $newOcations = array_merge($newOcations, $samepid);
                        break;
                    }
                }
            }
            // 初始化上一个地址级别
            $oldaddresslv = "";

            // 遍历处理每个教室的排课信息
            foreach ($newOcations as $room) {
                // 跳过非教室级别的地址（如楼栋、楼层等）
                if ($room['address_lv_octionlevel'] < 4) {
                    continue;
                }

                // 获取教室所属地址名称（如"教学点A"）
                $addresslv_obj = model("Ocation")->get($room['pid']);
                $addresslv = $addresslv_obj['name'] ?? '';

                // 解析当前教室的排课时间表数据
                $schedule2 = [];
                if (!empty($room['schedule_data'])) {
                    $schedule2 = json_decode($room['schedule_data'], true) ?: [];
                }

                // 检查当前教室是否有实际的课程安排
                $hasScheduledClasses = false;
                $roomName = trim(preg_replace("/\((?:标准|肢体|书画|综合)\)/Uisx", "", $room['name']));

                if (!empty($schedule2)) {
                    foreach ($schedule2 as $timeSlot) {
                        // 检查该教室在任何时间段是否有课程
                        foreach ($weekdays as $day) {
                            if (
                                isset($ocationsClass[$roomName][$day][$timeSlot['start_time']]) &&
                                !empty($ocationsClass[$roomName][$day][$timeSlot['start_time']])
                            ) {
                                $hasScheduledClasses = true;
                                break 2; // 跳出两层循环
                            }
                        }
                    }
                }

                // 如果当前教室没有实际排课，则跳过显示
                if (!$hasScheduledClasses) {
                    continue;
                }

                // 统计该地址下所有有课程的教室的有效时间段总数（用于rowspan计算）
                $addresslvsamecount = collection(model("Ocation")->where("pid", $room['pid'])->select())->toArray();
                $count = 0;

                foreach ($addresslvsamecount as $roomsamecount) {
                    if (isset($roomsamecount["schedule_data"]) && $roomsamecount["schedule_data"] != "") {
                        $scheduleData = json_decode($roomsamecount["schedule_data"], true) ?: [];
                        if (!empty($scheduleData)) {
                            // 检查该教室是否有实际的课程安排，并统计有效时间段
                            $roomNameCheck = trim(preg_replace("/\((?:标准|肢体|书画|综合)\)/Uisx", "", $roomsamecount['name']));
                            $validTimeSlotsCount = 0;

                            foreach ($scheduleData as $timeSlot) {
                                $hasClassInThisTimeSlot = false;
                                // 检查这个时间段在一周内是否有任何课程
                                foreach ($weekdays as $day) {
                                    if (
                                        isset($ocationsClass[$roomNameCheck][$day][$timeSlot['start_time']]) &&
                                        !empty($ocationsClass[$roomNameCheck][$day][$timeSlot['start_time']])
                                    ) {
                                        $hasClassInThisTimeSlot = true;
                                        break;
                                    }
                                }
                                if ($hasClassInThisTimeSlot) {
                                    $validTimeSlotsCount++;
                                }
                            }

                            $count += $validTimeSlotsCount;
                        }
                    }
                }

                // 处理禁用时段和禁用课节
                list($disabled_ranges, $disabled_times) = $this->parseDisableRanges(
                    $room['disable_week_range'] ?? '',
                    $room['disable_week_time'] ?? ''
                );
                // 开始新行，显示教室地址（如果与上一行不同）
                $message .= "\n<tr>";

                if ($addresslv != $oldaddresslv) {
                    // 地址级别变化时，添加跨行单元格显示地址
                    $message .= "<td rowspan='" . $count . "'>{$addresslv}</td>";
                    $oldaddresslv = $addresslv;
                }

                // 先过滤出有课程的时间段
                $validTimeSlots = [];
                foreach ($schedule2 as $time_name) {
                    $hasClassInThisTimeSlot = false;

                    // 检查这个时间段在一周内是否有任何课程
                    foreach ($weekdays as $day) {
                        $cell_content = $ocationsClass[$room["name"]][$day][$time_name['start_time']] ?? '';
                        if (!empty($cell_content)) {
                            $hasClassInThisTimeSlot = true;
                            break;
                        }
                    }

                    // 只保留有课程的时间段
                    if ($hasClassInThisTimeSlot) {
                        $validTimeSlots[] = $time_name;
                    }
                }

                // 如果没有任何有效时间段，跳过这个教室
                if (empty($validTimeSlots)) {
                    continue;
                }

                // 遍历有效的时间段
                $index = 1;
                foreach ($validTimeSlots as $time_name) {
                    // 如果是该教室的第一个时间段，显示教室名称（跨行合并）
                    if ($index == 1) {
                        $message .= "<td rowspan='" . count($validTimeSlots) . "'>{$room['name']}</td>";
                    } else {
                        $message .= "\n <tr>";  // 新行（不包含教室地址和名称）
                    }

                    // 显示时间段（如"08:00-09:30"）
                    $message .= "<td>{$time_name['start_time']}-{$time_name['end_time']}</td>";

                    // 为周一到周日生成单元格
                    foreach ($weekdays as $day) {
                        $is_disabled_range = false;

                        // 检查当前时段是否在禁用范围内
                        foreach ($disabled_ranges as $range) {
                            if ($range[0] == $day && $range[1] == $time_name) {
                                $is_disabled_range = true;
                                break;
                            }
                        }

                        // 检查当前课节是否在禁用课节中
                        foreach ($disabled_times as $range) {
                            if ($range[0] == $day && $range[1] == $time_name["oindex"]) {
                                $is_disabled_range = true;
                                break;
                            }
                        }

                        // 设置单元格样式（禁用时段显示灰色背景）
                        $style = $is_disabled_range ? 'background-color: #ccc;' : '';

                        // 获取该单元格的课程内容（如果有）
                        $cell_content = $ocationsClass[$room["name"]][$day][$time_name['start_time']] ?? '';

                        // 输出单元格
                        $message .= "<td style='$style'>$cell_content</td>";
                    }

                    // 结束当前行
                    $message .= "</tr>";
                    $index++;
                }
            }
            // 结束表格
            $message .= "</table>";

            // 准备返回的JSON数据
            $result["total"] = $total;      // 总记录数
            $result["message"] = $message;        // HTML格式的排课表
            $result["rows"] = $rows;              // 排课数据行

            // 将结果缓存到Redis
            $this->redis->setCacheData($cacheKey, $result, 3600); // 缓存1小时

            // 返回JSON响应
            return json($result);
        }

        //        $this->assignconfig("relType",$_REQUEST['relType']);
        //        $this->assignconfig("relId",$_REQUEST['relId']);
        $this->assignconfig("relType", $_REQUEST['relType'] ?? '1');
        $this->assignconfig("table_id", $table_id);
        $this->assignconfig("admin", $_SESSION['think']['admin']);
        // 添加isFormalSchedule到前端配置
        $this->assignconfig("isFormalSchedule", $this->model->isFormalSchedule($table_id));
        $this->assign("isFormalSchedule", $this->model->isFormalSchedule($table_id));
        $this->assign("table_id", $table_id);

        if ($this->view !== null) {
            return $this->view->fetch();
        }
        return '';
    }

    /**
     * 添加排课记录
     */
    public function add()
    {
        if ($this->request->isPost()) {
            $params = $this->request->post("row/a");
            if ($params) {
                if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
                    $params[$this->dataLimitField] = $this->auth->id;
                }
                try {
                    //是否采用模型验证
                    if ($this->modelValidate) {
                        $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
                        $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
                        $this->model->validate($validate);
                    }
                    // 自动插入session中的城市和学校ID
                    if (isset($_SESSION['think']['admin']['city_id']) && !empty($_SESSION['think']['admin']['city_id'])) {
                        $params['city_id'] = $_SESSION['think']['admin']['city_id'];
                    }
                    if (isset($_SESSION['think']['admin']['school_id']) && !empty($_SESSION['think']['admin']['school_id'])) {
                        $params['school_id'] = $_SESSION['think']['admin']['school_id'];
                    }

                    // 调试日志
                    error_log("Autoplan Add - Auto inserted city_id: " . ($params['city_id'] ?? 'null') . ", school_id: " . ($params['school_id'] ?? 'null'));

                    $datatime = date("Y-m-d H:i:s");
                    $params['create_time'] = $datatime;
                    unset($params['delete_time']);
                    unset($params['update_time']);
                    $params['date'] = (!array_key_exists("date", $params) || $params['date'] == "") ? date("Y-m-d", time()) : date("Y-m-d", strtotime($params['date']));
                    $result = $this->model->allowField(true)->save($params);
                    if ($result !== false) {
                        // 清除相关缓存
                        if (isset($params['table_id'])) {
                            $this->redis->clearCacheByTableId($params['table_id']);
                        }
                        // 添加成功后重定向并跳过缓存
                        $this->success('', null, ['skip_cache' => 1]);
                    } else {
                        $this->error($this->model->getError());
                    }
                } catch (\think\exception\PDOException $e) {
                    $this->error($e->getMessage());
                } catch (\think\Exception $e) {
                    $this->error($e->getMessage());
                }
            }
            $this->error(__('Parameter %s can not be empty', ''));
        }
        $this->assignconfig("admin", $_SESSION['think']['admin']);
        $this->assign("rel_type", $_SESSION['think']['admin']['rel_type'] ?? '');
        $this->assign("rel_id", $_SESSION['think']['admin']['rel_id'] ?? '');

        // 生成 leftOptions 和 rightOptions 的数据
        $data = array("args" => [[], [], []]);
        $leftOptions = $this->generateOptions('/user/user/lists', $data);
        $leftOptions = ($leftOptions == null) ? [] : $leftOptions["leftOptions"];
        $rightOptions = $this->generateOptions('/user/user/lists');
        $rightOptions = ($rightOptions == null) ? [] : $rightOptions["list"];
        $this->assignconfig("leftOptions", $leftOptions);
        $this->assignconfig("rightOptions", $rightOptions);

        if ($this->view !== null) {
            return $this->view->fetch();
        }
        return '';
    }

    /**
     * 编辑排课记录
     * 根据记录ID编辑排课信息，支持临时表和正式表的记录编辑
     */
    public
    function edit($ids = NULL)
    {
        // 先尝试从临时表获取记录
        $row = model("Autoplantemp")->get($ids);
        $table_id = null;
        $useFormalTable = false;

        if ($row) {
            $table_id = $row['table_id'];
            // 检查是否已有正式排课，如果有则操作正式表
            if ($this->hasFormalSchedule($table_id)) {
                $formalRow = $this->model->get($ids);
                if ($formalRow) {
                    $row = $formalRow;
                    $useFormalTable = true;
                }
            }
        } else {
            // 如果临时表没有，尝试从正式表获取
            $row = $this->model->get($ids);
            if ($row) {
                $table_id = $row['table_id'];
                $useFormalTable = true;
            }
        }

        if (!$row) {
            $this->error(__('No Results were found'));
        }

        if ($this->request->isPost()) {
            // 检查事件是否已过期（只在提交时检查）
            if ($this->isScheduleExpired($row)) {
                $this->error('由于已经是到期或过期的项目，所以不能更改和删除');
            }
        }

        $adminIds = $this->getDataLimitAdminIds();
        if (is_array($adminIds)) {
            if (!in_array($row[$this->dataLimitField], $adminIds)) {
                $this->error(__('You have no permission'));
            }
        }

        if ($this->request->isPost()) {
            $params = $this->request->post("row/a");
            if ($params) {
                try {
                    //是否采用模型验证
                    if ($this->modelValidate) {
                        $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
                        $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
                        //$row->validate($validate);
                    }
                    // 自动插入session中的城市和学校ID（如果当前记录没有设置的话）
                    if (isset($_SESSION['think']['admin']['city_id']) && !empty($_SESSION['think']['admin']['city_id'])) {
                        if (empty($row['city_id'])) {
                            $params['city_id'] = $_SESSION['think']['admin']['city_id'];
                        }
                    }
                    if (isset($_SESSION['think']['admin']['school_id']) && !empty($_SESSION['think']['admin']['school_id'])) {
                        if (empty($row['school_id'])) {
                            $params['school_id'] = $_SESSION['think']['admin']['school_id'];
                        }
                    }

                    // 调试日志
                    error_log("Autoplan Edit - Auto inserted city_id: " . ($params['city_id'] ?? 'null') . ", school_id: " . ($params['school_id'] ?? 'null'));

                    $datetime = time();
                    $params['update_time'] = $datetime;
                    unset($params['delete_time']);
                    unset($params['create_time']);

                    $params['date'] = (!array_key_exists("date", $params) || $params['date'] == "") ? date("Y-m-d", time()) : date("Y-m-d", strtotime($params['date']));
                    $params['teacher_id'] = join(",", $params['teacher_id']);
                    $params['manager_id'] = join(",", $params['manager_id']);
                    unset($params['table_id']); //课程名称不需要改
                    unset($params['event_name']); //课程名称不需要改
                    unset($params['ocourse_logo']); //课程封面不需要改
                    unset($params['event_content']); //课程内容不需要改
                    unset($params['classes_id']); //班级不需要改
                    unset($params['course_type']); //课堂类型不需要改
                    unset($params['daytime']); //时段选择不需要改

                    $result = $row->allowField(true)->save($params);

                    if ($result !== false) {
                        // 清除相关缓存
                        if ($table_id) {
                            $this->redis->clearCacheByTableId($table_id);
                        }
                        // 编辑成功后重定向并跳过缓存
                        $this->success('', null, ['skip_cache' => 1]);
                    } else {
                        $this->error($row->getError());
                    }
                } catch (\think\exception\PDOException $e) {
                    $this->error($e->getMessage());
                } catch (\think\Exception $e) {
                    $this->error($e->getMessage());
                }
            }
            $this->error(__('Parameter %s can not be empty', ''));
        }

        //项目课程事件
        $coursetable = model("Coursetable")->get($row['table_id']);
        $table_id_name = $coursetable['name'];
        $row['start_date'] = $coursetable['start_date'] ? substr($coursetable['start_date'], 0, 10) : '';
        $row['end_date'] = $coursetable['end_date'] ? substr($coursetable['end_date'], 0, 10) : '';
        $row['exclint_holidays'] = $coursetable['exclint_holidays'] ? substr($coursetable['exclint_holidays'], 0, 10) : '';
        //事件的日期$row['date'];
        //事件的日期$row['week'];
        //事件的日期课节开始时间$row['start_time'];
        //事件的日期课节结束时间$row['end_time'];
        //事件的日期课节,当天第几节课？ $row['class_index'];
        $time = new \DateTime($row['date'] . " " . $row['start_time']);
        $interval = new \DateInterval('PT30M');
        $time->sub($interval);
        //课前打卡时间:
        $row['prechenkintime'] = $time->format('Y-m-d H:i');
        $time = new \DateTime($row['date'] . " " . $row['end_time']);
        $interval = new \DateInterval('PT30M');
        $time->add($interval);
        //课后打卡时间
        $row['prechenkouttime'] = $time->format('Y-m-d H:i');
        $time = new \DateTime($row['date'] . " " . $row['end_time']);
        $interval = new \DateInterval('PT12H');
        $time->add($interval);
        //评价开始时间
        $row['evalstart'] = $row['date'] . " " . $row['end_time'];
        //评价结束时间
        $row['evalend'] = $time->format('Y-m-d H:i');
        $row['ocourse_count'] = 0;
        //老师岗 $row['teacher_id']
        //管理岗 $row['manager_id']

        //班级
        $classes = model("Classes")->get($row['classes_id']);
        //班级名称 $classes["name"];
        //课程名称等于事件的名称 $classes["name"];
        $row["event_name"] = $classes["name"];
        //课程封面也就是等于事件的封面 $classes["name"];
        $row["ocourse_logo"] = $classes["cover"];
        $row["event_content"] = trim(strip_tags($classes["intro"]));

        //教学点设置
        $ocation = model("Ocation")->where("id", "=", $row["ocation_id"])->select();
        //教室 $ocation["name"]
        //上课地址 $row["address"]
        $addresslv_id_B = null;
        if (!empty($ocation) && isset($ocation[0]["pid"])) {
            $addresslv_id_B = model("Ocation")->get($ocation[0]["pid"]);
        }
        //二级教学点地址
        if ($addresslv_id_B && is_array($addresslv_id_B)) {
            $row['addresslv_id_B'] = $addresslv_id_B["name"];

            // 获取一级教学点地址
            if (isset($addresslv_id_B["pid"])) {
                $addresslv_id_A = model("Ocation")->get($addresslv_id_B["pid"]);
                if ($addresslv_id_A && is_array($addresslv_id_A)) {
                    $row['addresslv_id_A'] = $addresslv_id_A["name"];
                }
            }
        }

        //一周几次课
        $row['classes_per_week'] = (!empty($ocation) && isset($ocation[0]["classes_per_week"])) ? $ocation[0]["classes_per_week"] : 0;

        //学科设置
        $subjectlv = model("Subjectlv")->where("id", "=", $row["subject_lv"])->select();
        if (isset($subjectlv[0]["name"])) {
            $row["subjectlv"] = $subjectlv[0]["name"];
        } else {
            $row["subjectlv"] = ""; // 或者给个默认值
        }
        if (!empty($subjectlv) && isset($subjectlv[0]["pid"])) {
            $subjectlv_id_B = model("Subjectlv")->get($subjectlv[0]["pid"]);
        } else {
            $subjectlv_id_B = null; // 或者给个默认值
        }
        //二级学科
        if ($subjectlv_id_B && isset($subjectlv_id_B["name"])) {
            $row['addresslv_id_B'] = $subjectlv_id_B["name"];
        } else {
            $row['addresslv_id_B'] = ""; // 或者其他默认值
        }
        //一级学科
        if ($subjectlv_id_B && isset($subjectlv_id_B["pid"])) {
            $subjectlv_id_A = model("Subjectlv")->get($subjectlv_id_B["pid"]);
        } else {
            $subjectlv_id_A = null; // 或者给个默认值
        }
        if ($subjectlv_id_A == null) {
            $row['subjectlv_id_A'] = $row["subjectlv"];
            $row['subjectlv_id_B'] = "";
        } elseif ($subjectlv_id_A["pid"] == 0) {
            $row['subjectlv_id_A'] = $subjectlv_id_B["name"];
            $row['subjectlv_id_B'] = isset($subjectlv[0]["name"]) ? $subjectlv[0]["name"] : "";
        } else {
            $row['subjectlv_id_A'] = $subjectlv_id_A["name"];
        }

        //课程设置
        $classplant = model("Classplant")->where("table_id", "=", $coursetable['id'])->where("classes_id", "=", $row["classes_id"])->select();
        if (array_key_exists("0", $classplant)) {
            //课程长度:
            $row['ocourse_count'] = $classplant[0]["ocourse_count"];
            $row['ocation_type'] = $classplant[0]["ocation_type"];
            $row['suject_lv'] = model("Subjectlv")->getSubject_lvTextAttr($classplant[0]["subject_lv"]);
        }
        //周几 $classplant['week'];
        //时段 上午 中午 下午 晚上 $classplant['daytime'];
        //当天第几节课 $classplant['oindex'];
        //开始上课时间 $classplant['start_time'];
        //下课时间 $classplant['end_time'];
        //起始日期 $classplant['start_date'];
        //结束日期 $classplant['end_date'];
        //是否排除国际假日 $classplant['exclint_holidays'];
        //是否同一间教室 $classplant['same_classroom'];
        //是否同一教学点 $classplant['same_ocation'];
        //能否排在同一天 $classplant['can_same_day'];
        //时段选择 $classplant['daytime'];


        $this->assignconfig("admin", $_SESSION['think']['admin']);

        if ($this->view !== null) {
            // 检查是否过期并传递给视图
            $isExpired = $this->isScheduleExpired($row);
            $this->view->assign("row", $row);
            $this->view->assign("table_id_name", $table_id_name);
            $this->view->assign("rel_type", $_SESSION['think']['admin']['rel_type'] ?? '');
            $this->view->assign("rel_id", $_SESSION['think']['admin']['rel_id'] ?? '');
            $this->view->assign("isExpired", $isExpired);
        }

        $teacherIds = !empty($row['teacher_id']) ? explode(",", $row['teacher_id']) : [];
        $managerIds = !empty($row['manager_id']) ? explode(",", $row['manager_id']) : [];
        $data = array("args" => [[], $teacherIds, $managerIds]);

        $leftOptions = $this->generateOptions('/user/user/lists', $data);
        $leftOptions = ($leftOptions == null) ? [] : $leftOptions["leftOptions"];
        $rightOptions = $this->generateOptions('/user/user/lists');
        $rightOptions = ($rightOptions == null) ? [] : $rightOptions["list"];
        $this->assignconfig("leftOptions", $leftOptions);
        $this->assignconfig("rightOptions", $rightOptions);

        if ($this->view !== null) {
            return $this->view->fetch();
        }
        return '';
    }

    /**
     * 查看排课详情
     */
    public
    function view($ids = NULL)
    {
        $row = $this->model->getRow($ids);

        if ($this->view !== null) {
            $this->view->assign("row", $row);
            return $this->view->fetch();
        }
        return '';
    }

    /**
     * 获取排课列表
     */
    public
    function lists($ids = NULL)
    {
        $where = "where 1=1";
        if (($_SESSION['think']['admin']['group_id'] ?? 0) != 1) {
            $where .= " and city_id='" . ($_SESSION['think']['admin']['city_id'] ?? '') . "'";
        }
        $page = 1;
        $pagesize = 50;
        if ($this->request->isAjax()) {
            if ($this->request->request('keyField')) {
                $keyField = $this->request->request("keyField");
                $keyValue = $this->request->request("keyValue");
                $page = $this->request->request("pageNumber");
                $page = ($page == null) ? 1 : $page;
                $pagesize = $this->request->request("pageSize");
                $pagesize = ($pagesize == null) ? 10 : $pagesize;
                if ($keyValue != "") {
                    $nn = preg_split("/\,/", $keyValue);
                    for ($i = 0; $i < count($nn); $i++) {
                        $where .= " and $keyField='{$nn[$i]}'";
                    }
                }
            } else {
                $where = "where status=1";
                if (isset($_REQUEST['city_id']) && $_REQUEST['city_id'] > 0) {
                    //$where.=" and city_id=".$_REQUEST['city_id'];
                }
            }
        }
        $sql = "select id,week name from dev002_gxyusheng.fa_course_table_autoplan $where limit " . (($page - 1) * $pagesize) . ",$pagesize";
        $list = db()->query($sql);

        //        $r_name = model("School")->field("id,name")->where("id", "=", $_REQUEST['school_id'])->select();
        //        if (empty($list)&&!empty($r_name)) {
        //            $data = array(
        //                "type" => "file",
        //                "pid" => 0,
        //                "name" => $r_name[0]['name']."学科",
        //                "title" => $r_name[0]['name'],
        //                "ismenu" => 0,
        //                "createtime" => time(),
        //                "updatetime" => time(),
        //                "status" => 1,
        //                "school_id" => $_REQUEST['school_id'],
        //            );
        //            $this->model->create($data);
        //        }
        //        $sql="select id,pid,name,title,status from dev002_gxyusheng.fa_course_table_autoplan $where limit " . (($page - 1) * $pagesize) . ",$pagesize";
        //        $list = db()->query($sql);
        //        $tree = Tree::instance();
        //        $tree->init($list, 'pid');
        //        $list = $tree->getTreeList($tree->getTreeArray(0), 'name');

        $total = db()->query("select count(1) as c from  dev002_gxyusheng.fa_course_table_autoplan $where")[0];
        echo json_encode(array("list" => $list, "total" => $total['c']));
        exit;
    }

    /**
     * 切换排课状态
     */
    public
    function status($ids = '')
    {
        $ids = $this->request->post('ids');
        if (empty($ids)) {
            return json([
                'code' => 0,
                'msg' => '没有选中!',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        try {
            $result = $this->model->where("id", "=", $ids)->field("status")->find();
            $v = $result->status == 1 ? 0 : 1;
            $this->model->where("id", "=", $ids)->update(["status" => $v]);
            return json([
                'code' => 1,
                'msg' => '切换成功!',
                'data' => ['new_status' => $v],
                'url' => null,
                'wait' => 3
            ]);
        } catch (Exception $e) {
            return json([
                'code' => 0,
                'msg' => '切换失败!' . $e->getMessage(),
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 更改排课状态
     */
    public
    function changeStatus($ids = '')
    {
        $ids = $this->request->post('ids');
        if (empty($ids)) {
            return json([
                'code' => 0,
                'msg' => '没有选中!',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
        try {
            $result = $this->model->where("id", "=", $ids)->field("status")->find();
            $v = $result->status == 1 ? 0 : 1;
            $this->model->where("id", "=", $ids)->update(["status" => $v]);
            return json([
                'code' => 1,
                'msg' => '切换成功!',
                'data' => ['new_status' => $v],
                'url' => null,
                'wait' => 3
            ]);
        } catch (Exception $e) {
            return json([
                'code' => 0,
                'msg' => '切换失败!' . $e->getMessage(),
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 导出排课数据
     * @param string $ids 要导出的排课记录ID，多个ID用逗号分隔
     */
    public function export($ids)
    {
        // 获取数据
        $list = model("Autoplantemp")->where("id", "in", $ids)->select();

        // 设置导出文件名
        $filename = '课程计划详情表' . date('YmdHis');

        // 设置表头
        $headers = [
            'Id',
            '项目名称',
            '班名',
            '教室',
            '课程',
            '老师',
            '时段',
            '日期',
            '时间',
            '周几',
            '课节',
            '备注',
        ];

        // 设置数据
        $data = [];
        foreach ($list as $item) {
            $ocation = model("Ocation")->get($item['ocation_id']);
            $courseable = model("Coursetable")->get($item['table_id']);
            $classes = model("Classes")->get($item['classes_id']);
            $data[] = [
                $item['id'],
                $courseable['name'],
                $classes['name'],
                $ocation['name'],
                model("Subjectlv")->getSubjectlv_idTextAttr($item['subject_lv']),
                model("User")->getUser_idTextAttr($item['teacher_id']),
                $item['daytime'],
                $item['date'] . " ",
                $item['start_time'] . " - " . $item['end_time'],
                $item['week'],
                $item['class_index'] . "/" . $item['count_total'],
                $item['bz'],
            ];
        }

        // 调用导出方法
        $this->exportExcel($filename, $headers, $data);
    }

    /**
     * 导出Excel文件
     * @param string $filename 导出文件名
     * @param array $headers 表头数据
     * @param array $data 表格数据
     */
    protected function exportExcel($filename, $headers, $data)
    {
        // 创建一个新的Spreadsheet对象
        $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        // 设置工作表标题
        $sheet->setTitle("课程安排");

        // 添加标题，并合并A1到K1单元格，设置居中
        $title = '课程计划详情';
        $sheet->mergeCells('A1:K1');
        $sheet->setCellValue('A1', $title);
        $sheet->getStyle('A1')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
        $sheet->getStyle('A1')->getFont()->setBold(true);

        // 设置表头
        $sheet->fromArray($headers, null, 'A2');
        // 设置数据
        $sheet->fromArray($data, null, 'A3');

        // 应用边框样式
        $styleArray = [
            'borders' => [
                'outline' => [
                    'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
                    'color' => ['argb' => '000000'],
                ],
                'inside' => [
                    'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                    'color' => ['argb' => '000000'],
                ],
            ],
        ];

        $lastRow = $sheet->getHighestRow();
        $lastColumn = $sheet->getHighestColumn();
        $sheet->getStyle('A1:' . $lastColumn . $lastRow)->applyFromArray($styleArray);

        // 设置表头颜色为#ccc
        $sheet->getStyle('A2:' . $lastColumn . '2')->getFill()
            ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
            ->getStartColor()->setARGB('FFCCCCCC');  // #ccc in ARGB format

        // 启用筛选功能
        $sheet->setAutoFilter('A2:' . $lastColumn . '2');

        // 设置列宽为内容自适应
        foreach (range('A', $sheet->getHighestColumn()) as $column) {
            $sheet->getColumnDimension($column)->setAutoSize(true);
        }

        // 设置响应头
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $filename . '.xlsx"');
        header('Cache-Control: max-age=0');

        // 输出文件
        $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
        $writer->save('php://output');
        exit;
    }


    /**
     * 删除排课记录
     * 支持从临时表或正式表删除排课记录
     * @param string $ids 要删除的排课记录ID，多个ID用逗号分隔
     */
    function del($ids = null)
    {
        $ids = $this->request->post('ids');
        if (empty($ids)) {
            return json([
                'code' => 0,
                'msg' => '没有选中!',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        try {
            $tableIds = [];
            $deletedCount = 0;

            // 先检查每个记录的table_id，判断应该从哪个表删除
            foreach (explode(',', $ids) as $id) {
                $id = trim($id);
                if (empty($id)) continue;

                // 先从临时表查找记录
                $tempRecord = model("Autoplantemp")->where("id", $id)->find();

                // 检查记录是否过期
                if ($tempRecord && $this->isScheduleExpired($tempRecord)) {
                    return json([
                        'code' => 0,
                        'msg' => '由于已经是到期或过期的项目，所以不能更改和删除',
                        'data' => null,
                        'url' => null,
                        'wait' => 3
                    ]);
                }
                if ($tempRecord) {
                    $table_id = $tempRecord['table_id'];
                    if (!in_array($table_id, $tableIds)) {
                        $tableIds[] = $table_id;
                    }

                    // 检查是否有正式排课，如果有则从正式表删除，否则从临时表删除
                    if ($this->hasFormalSchedule($table_id)) {
                        // 从正式表删除
                        $result = $this->model->where("id", $id)->delete();
                        if ($result) {
                            $deletedCount++;
                        }
                    } else {
                        // 从临时表删除
                        $result = model("Autoplantemp")->where("id", $id)->delete();
                        if ($result) {
                            $deletedCount++;
                        }
                    }
                } else {
                    // 临时表没有，尝试从正式表删除
                    $formalRecord = $this->model->where("id", $id)->find();
                    if ($formalRecord) {
                        // 检查正式表记录是否过期
                        if ($this->isScheduleExpired($formalRecord)) {
                            return json([
                                'code' => 0,
                                'msg' => '由于已经是到期或过期的项目，所以不能更改和删除',
                                'data' => null,
                                'url' => null,
                                'wait' => 3
                            ]);
                        }

                        $table_id = $formalRecord['table_id'];
                        if (!in_array($table_id, $tableIds)) {
                            $tableIds[] = $table_id;
                        }
                        $result = $this->model->where("id", $id)->delete();
                        if ($result) {
                            $deletedCount++;
                        }
                    }
                }
            }

            // 清除相关缓存
            foreach ($tableIds as $tableId) {
                $this->redis->clearCacheByTableId($tableId);
            }

            return json([
                'code' => 1,
                'msg' => '删除成功，共删除 ' . $deletedCount . ' 条记录!',
                'data' => ['skip_cache' => 1], // 删除成功后标记跳过缓存
                'url' => null,
                'wait' => 3
            ]);
        } catch (Exception $e) {
            return json([
                'code' => 0,
                'msg' => '删除失败!' . $e->getMessage(),
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 重新排课
     * 清空指定项目的临时排课数据，触发重新排课
     */
    function redo()
    {
        $table_id = $this->request->param('table_id');
        try {
            $result = Db::name('fa_course_table_autoplan_temp')
                ->where('table_type', 1)
                ->where('table_id', $table_id)->delete();

            // 清除相关缓存
            $this->redis->clearCacheByTableId($table_id);

            return json([
                'code' => 1,
                'msg' => '已经清空全部旧排课信息，正在重新生成排课信息!',
                'data' => ['table_id' => $table_id],
                'url' => null,
                'wait' => 3
            ]);
        } catch (Exception $e) {
            return json([
                'code' => 1,
                'msg' => '已经清空全部旧排课信息，正在重新生成排课信息!',
                'data' => ['table_id' => $table_id],
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 取消正式排课
     * 删除正式排课表中的数据，需要密码验证
     */
    public function cancelSchedule()
    {
        if (!$this->request->isPost()) {
            return json([
                'code' => 0,
                'msg' => '非法请求方式',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        $table_id = $this->request->post('table_id', 0);
        $password = $this->request->post('password', '');

        if (!$table_id) {
            \think\Log::record('cancelSchedule失败：项目ID为空', 'error');
            return json([
                'code' => 0,
                'msg' => '项目ID不能为空',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        // 验证密码
        if (!$this->validateSchedulePassword($password)) {
            \think\Log::record('cancelSchedule失败：密码验证失败 table_id=' . $table_id, 'error');
            return json([
                'code' => 0,
                'msg' => '密码错误，无法执行取消正式排课操作',
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }

        // 清除相关缓存
        $this->redis->clearCacheByTableId($table_id);
        // 记录操作开始
        $userId = 0;
        try {
            $user = $this->auth->getUserInfo();
            $userId = is_array($user) && isset($user['id']) && is_scalar($user['id']) ? $user['id'] : 0;
        } catch (\Exception $e) {
            $userId = 0;
        }

        \think\Log::record('开始取消正式排课 table_id=' . $table_id . ' user_id=' . $userId, 'info');

        // 开始事务
        Db::startTrans();
        try {
            // 检查项目是否存在
            $project = Db::name('course_table')
                ->where('id', $table_id)
                ->find();

            if (!$project) {
                Db::rollback();
                \think\Log::record('cancelSchedule失败：项目不存在 table_id=' . $table_id, 'error');
                return json([
                    'code' => 0,
                    'msg' => '指定的项目不存在',
                    'data' => null,
                    'url' => null,
                    'wait' => 3
                ]);
            }

            // 检查正式表中是否有数据
            $formalCount = Db::name('course_table_autoplan')
                ->where('table_id', $table_id)
                ->count();


            if ($formalCount == 0) {
                Db::rollback();
                \think\Log::record('cancelSchedule失败：正式表无数据 table_id=' . $table_id, 'error');
                return json([
                    'code' => 0,
                    'msg' => '该项目没有正式排课数据，无需取消',
                    'data' => null,
                    'url' => null,
                    'wait' => 3
                ]);
            }

            \think\Log::record('找到正式排课数据 table_id=' . $table_id . ' count=' . $formalCount, 'info');

            // 删除正式表中的数据
            \think\Log::record('开始删除正式排课数据 table_id=' . $table_id, 'info');

            $deleteResult = Db::name('course_table_autoplan')
                ->where('table_id', $table_id)
                ->delete();

            if ($deleteResult === false) {
                throw new \Exception('删除正式排课数据失败');
            }

            \think\Log::record('删除正式排课数据成功 table_id=' . $table_id . ' deleted_count=' . $deleteResult, 'info');

            // 提交事务
            Db::commit();

            // 记录成功日志
            \think\Log::record('取消正式排课成功 table_id=' . $table_id . ' deleted_count=' . $deleteResult . ' user_id=' . $userId, 'info');

            $message = '取消正式排课成功，共删除 ' . $deleteResult . ' 条记录';
            return json([
                'code' => 1,
                'msg' => $message,
                'data' => [
                    'table_id' => $table_id,
                    'deleted_count' => $deleteResult,
                    'project_name' => $project['name'] ?? ''
                ],
                'url' => null,
                'wait' => 3
            ]);
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();

            // 记录详细错误日志
            \think\Log::record('取消正式排课失败 table_id=' . $table_id . ' error=' . $e->getMessage() . ' user_id=' . $userId, 'error');

            return json([
                'code' => 0,
                'msg' => '取消正式排课失败：' . $e->getMessage(),
                'data' => null,
                'url' => null,
                'wait' => 3
            ]);
        }
    }

    /**
     * 验证正式排课密码
     * 用于取消正式排课操作的身份验证
     * @param string $password 用户输入的密码
     * @return bool
     */
    private function validateSchedulePassword($password)
    {
        // 设置正式排课密码（可以从配置文件或数据库读取）
        $correctPassword = config('schedule_password') ?: '1594561';

        // 临时调试日志 - 记录密码验证详情
        \think\Log::record('密码验证调试 - 输入密码: [' . $password . '] 长度: ' . strlen($password) . ' 正确密码: [' . $correctPassword . '] 长度: ' . strlen($correctPassword), 'info');
        \think\Log::record('密码验证调试 - 输入密码十六进制: ' . bin2hex($password) . ' 正确密码十六进制: ' . bin2hex($correctPassword), 'info');

        $result = $password === $correctPassword;
        \think\Log::record('密码验证调试 - 验证结果: ' . ($result ? '通过' : '失败'), 'info');

        return $result;
    }


}
